#ifndef DWARF__RAII_POINTER_H
#define DWARF__RAII_POINTER_H

#include <cstddef>

#include <libdwarf/libdwarf.h>

namespace dwarf {

template<typename _Pointer>
class RaiiPointer {
protected:
	Dwarf_Debug debug_;
	Dwarf_Unsigned type_;
	_Pointer pointer_;
public:
	RaiiPointer(Dwarf_Debug _debug, _Pointer _pointer);
	RaiiPointer(Dwarf_Debug _debug);
	RaiiPointer(const RaiiPointer &_raiiPointer);
	virtual ~RaiiPointer();
private:
	RaiiPointer &operator=(const RaiiPointer &_raiiPointer);
public:
	_Pointer &getPointer();
	const _Pointer &getPointer() const;
};

template<typename _Pointer>
RaiiPointer<_Pointer>::RaiiPointer(const RaiiPointer &_raiiPointer)
		: debug_(_raiiPointer.debug_),
		  type_(_raiiPointer.type_),
		  pointer_(_raiiPointer.pointer_) {
	if (this == &_raiiPointer) {
		return;
	}
	((RaiiPointer *) &_raiiPointer)->pointer_ = NULL;
}

template<typename _Pointer>
RaiiPointer<_Pointer> &RaiiPointer<_Pointer>::operator=(const RaiiPointer &_raiiPointer) {
	debug_ = _raiiPointer.debug_;
	type_ = _raiiPointer.type_;
	pointer_ = _raiiPointer.pointer_;
	if (this == &_raiiPointer) {
		return *this;
	}
	((RaiiPointer *) &_raiiPointer)->pointer_ = NULL;
	return *this;
}

template<typename _Pointer>
RaiiPointer<_Pointer>::~RaiiPointer() {
	if (pointer_ == NULL) {
		return;
	}
	dwarf_dealloc(debug_, pointer_, type_);
}

template<typename _Pointer>
_Pointer &RaiiPointer<_Pointer>::getPointer() {
	return pointer_;
}

template<typename _Pointer>
const _Pointer &RaiiPointer<_Pointer>::getPointer() const {
	return pointer_;
}

}

#endif // DWARF__RAII_POINTER_H
